package fxification.db;

import fxification.java.FxSql;
import java.lang.Throwable;
import java.sql.Statement;
import javafx.data.Pair;
import java.sql.ResultSet;

/**
This is a JDBC wrapper class.
**/
public class Sql {
    public-init var connection:java.sql.Connection;
    public-init var dataSource:javax.sql.DataSource;
    public-init var properties:Pair[];
    public-init var url:String;
    public-init var driver:String;
    public-init var username:String;
    public-init var password:String;
    public-init var sql:String;
    
    public var onFailure:function(:Throwable);
    public var onStartingQuery:function(:Statement);
    public var onDataSetAvailable:function(:DataSet);
    public var onEachRow:function(:DataSet.Row);
    public var onResultSetAvailable:function(:ResultSet);
    public var onUpdateCompleted:function(:Integer);

    init {
        if(dataSource != null){
            connection = dataSource.getConnection();
        }else if(connection == null){
           connection = FxSql.getConnection(driver, url, username, password, properties);
        }
    }

    public function query(){

        FxSql.queryForDataSet(
            connection,
            sql,
            onStartingQuery,
            onEachRow,
            onDataSetAvailable,
            onResultSetAvailable,
            onFailure);
    }

    public function execute(){query()} // alias for query

    public function doWithEachRow(fn:function(:DataSet.Row)){
        this.onEachRow = fn;
        this.onFailure = function(e:Throwable){e.printStackTrace();}
        this.query();
    }

    public function doWithDataSet(fn:function(:DataSet)){
        this.onDataSetAvailable = fn;
        this.onFailure = function(e:Throwable){e.printStackTrace();}
        this.query();
    }

    public function doWithResultSet(fn:function(:ResultSet)){
        this.onFailure = function(ex:Throwable){ex.printStackTrace();}
        this.onResultSetAvailable = fn;
        this.query();
    }

    public function getRows(sql:String):DataSet.Row[]{
        var rows:DataSet.Row[];
        this.query();
        this.onDataSetAvailable = function(ds:DataSet){rows = ds.getRows();}
        this.onFailure = function(ex:Throwable){ex.printStackTrace();}
        rows;
    }

    public function update(){
        FxSql.updateQuery(
            connection, 
            sql,
            onStartingQuery,
            onDataSetAvailable,
            onResultSetAvailable,
            onUpdateCompleted,
            onFailure);
    }

    // future version
    public function call(proc:String, params:Param[]){}
}

public class Param {
    public def IN:Integer = 0;
    public def OUT:Integer = 1;

    public-init var value:Object;
    public-init var type:Integer;
    public var direction = Param.IN;
}

public var ARRAY:Param = Param{value:null type:java.sql.Types.ARRAY direction:1};
public function ARRAY(v:Object):Param {Param{value:v type:java.sql.Types.ARRAY}}


public function BIGINT(v:Object):Param {Param{value:v type:java.sql.Types.BIGINT}}
public function BIGINT():Param{Param{value:null type:java.sql.Types.BIGINT direction:1}}

public function BINARY(v:Object):Param {Param{value:v type:java.sql.Types.BINARY}}
public function BINARY():Param{Param{value:null type:java.sql.Types.BINARY direction:1}}


